/*
 * FaceCat图形通讯框架
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "../../include/date/YearDiv.h"
#include "../../stdafx.h"
#include "../../include/div/FCDiv.h"
#include "../../include/grid/FCGridColumn.h"

namespace FaceCat{
	FCDiv::FCDiv(){
		m_allowDragScroll = false;
		m_hScrollBar = 0;
		m_isDragScrolling = false;
		m_isDragScrolling2 = false;
		m_mustUpdate = false;
		m_readyToDragScroll = false;
		m_showHScrollBar = false;
		m_showVScrollBar = false;
		m_startMovePoint.x = 0;
		m_startMovePoint.y = 0;
		m_startMovePosX = 0;
		m_startMovePosY = 0;
		m_startMoveTime = 0;
		m_vScrollBar = 0;
		FCSize size = {100, 100};
		m_size = size;
	}

	FCDiv::~FCDiv(){
		m_hScrollBar = 0;
		m_vScrollBar = 0;
	}

	bool FCDiv::allowDragScroll(){
		return m_allowDragScroll;
	}

	void FCDiv::setAllowDragScroll(bool value){
		m_allowDragScroll = value;
	}

	FCHScrollBar* FCDiv::getHScrollBar(){
		if (getNative() && m_showHScrollBar){
            if (!m_hScrollBar){
				FCHost *host = getNative()->getHost();
                m_hScrollBar = dynamic_cast<FCHScrollBar*>(host->createInternalView(this, L"hscrollbar"));
                addView(m_hScrollBar);
				m_hScrollBar->getAddButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_hScrollBar->getAddButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_hScrollBar->getBackButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_hScrollBar->getBackButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_hScrollBar->getReduceButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_hScrollBar->getReduceButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_hScrollBar->getScrollButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_hScrollBar->getScrollButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
            }
            return m_hScrollBar;
        }
        return 0;
	}

	bool FCDiv::showHScrollBar(){
		return m_showHScrollBar;
	}

	void FCDiv::setShowHScrollBar(bool value){
		m_showHScrollBar = value;
	}

	bool FCDiv::isDragScrolling(){
		return m_isDragScrolling;
	}

	bool FCDiv::showVScrollBar(){
		return m_showVScrollBar;
	}

	void FCDiv::setShowVScrollBar(bool value){
		m_showVScrollBar = value;
	}

	FCVScrollBar* FCDiv::getVScrollBar(){
        if (getNative() && m_showVScrollBar){
            if (!m_vScrollBar){
				FCHost *host = getNative()->getHost();
                m_vScrollBar = dynamic_cast<FCVScrollBar*>(host->createInternalView(this, L"vscrollbar"));
                addView(m_vScrollBar);
				m_vScrollBar->getAddButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_vScrollBar->getAddButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_vScrollBar->getBackButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_vScrollBar->getBackButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_vScrollBar->getReduceButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_vScrollBar->getReduceButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
				m_vScrollBar->getScrollButton()->addEvent((FCKeyEventCallBack*)this, L"onkeydown", this);
				m_vScrollBar->getScrollButton()->addEvent((FCTouchEventCallBack*)this, L"ontouchwheel", this);
            }
            return m_vScrollBar;
        }
        return 0;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    void FCDiv::callEvent(String eventName, Object sender, Object invoke) {
    }

    void FCDiv::callKeyEvent(String eventName, Object sender, char key, Object invoke) {
        if (m_hScrollBar) {
            for (int i = 0; i < m_hScrollBar->m_views.size(); i++) {
                if (m_hScrollBar->m_views.get(i) == sender) {
                    onKeyDown(key);
                    return;
                }
            }
        }
        if (m_vScrollBar) {
            for (int i = 0; i < m_vScrollBar->m_views.size(); i++) {
                if (m_vScrollBar->m_views.get(i) == sender) {
                    onKeyDown(key);
                    return;
                }
            }
        }
    }

    void FCDiv::callTouchEvent(String eventName, Object sender, FCTouchInfo touchInfo, Object invoke) {
        FCTouchInfo newTouchInfo = touchInfo;
        newTouchInfo.m_firstPoint = getTouchPoint();
        newTouchInfo.m_secondPoint = getTouchPoint();
        onTouchWheel(newTouchInfo);
    }

	void FCDiv::clearChildViews(){
		ArrayList<FCView*> views;
		int viewsSize = (int)m_views.size();
		for(int c = 0; c < m_views.size(); c++){
			if(m_views.get(c) != m_hScrollBar && m_views.get(c) != m_vScrollBar){
				views.add(m_views.get(c));
			}
		}
		for(int c = 0; c < views.size(); c++){
			FCView *view = views.get(c);
			removeView(view);
			delete view;
		}
		views.clear();
	}

	int FCDiv::getContentHeight(){
		if (!m_showVScrollBar)
        {
            return getHeight();
        }
		FCHScrollBar *hScrollBar = getHScrollBar();
		FCVScrollBar *vScrollBar = getVScrollBar();
		int hmax = 0;
		ArrayList<FCView*> views = getViews();
		for(int c = 0; c < views.size(); c++){
			FCView *view = views.get(c);
			if (view->isVisible() && view != hScrollBar && view != vScrollBar){
				int bottom = view->getBottom();
				if (bottom > hmax){
					hmax = bottom;
				}
			}
		}
		return hmax;
	}

	int FCDiv::getContentWidth(){
		if (!m_showHScrollBar)
        {
            return getWidth();
        }
		FCHScrollBar *hScrollBar = getHScrollBar();
		FCVScrollBar *vScrollBar = getVScrollBar();
		int wmax = 0;
		ArrayList<FCView*> views = getViews();
		for(int c = 0; c < views.size(); c++){
			FCView *view = views.get(c);
			if (view->isVisible() && view != hScrollBar && view != vScrollBar){
				int right = view->getRight();
				if (right > wmax){
					wmax = right;
				}
			}
		}
		return wmax;
	}

	String FCDiv::getViewType(){
		return L"Div";
	}

	FCPoint FCDiv::getDisplayOffset(){
		FCPoint offset = {(m_hScrollBar && m_hScrollBar->isVisible()) ? m_hScrollBar->getPos() : 0, (m_vScrollBar && m_vScrollBar->isVisible()) ? m_vScrollBar->getPos() : 0};
		return offset;
	}

	void FCDiv::getAttribute(const String& name, String *value, String *type){
		if (name == L"allowdragscroll"){
			*type = L"bool";
			*value = FCTran::boolToStr(allowDragScroll());
		}
	    else if (name == L"showhscrollbar"){
			*type = L"bool";
			*value = FCTran::boolToStr(m_showHScrollBar);
		}
		else if(name == L"showvscrollbar"){
			*type = L"bool";
			*value = FCTran::boolToStr(m_showVScrollBar);
		}
		else{
			FCView::getAttribute(name, value, type);
		}
	}

	ArrayList<String> FCDiv::getAttributeNames(){
		ArrayList<String> attributeNames = FCView::getAttributeNames();
		attributeNames.add(L"AllowDragScroll");
		attributeNames.add(L"ShowHScrollBar");
		attributeNames.add(L"ShowVScrollBar");
		return attributeNames;
	}

	void FCDiv::lineDown(){
		if (m_vScrollBar && m_vScrollBar->isVisible()){
			m_vScrollBar->lineAdd();
		}
	}

	void FCDiv::lineLeft(){
		if (m_hScrollBar && m_hScrollBar->isVisible()){
			m_hScrollBar->lineReduce();
		}
	}

	void FCDiv::lineRight(){
		if (m_hScrollBar && m_hScrollBar->isVisible()){
			m_hScrollBar->lineAdd();
		}
	}

	void FCDiv::lineUp(){
		if (m_vScrollBar && m_vScrollBar->isVisible()){
			m_vScrollBar->lineReduce();
		}
	}

	void FCDiv::onDragReady(FCPoint *startOffset){
		startOffset->x = 0;
		startOffset->y = 0;
	}

	void FCDiv::onDragScrollEnd(){
		m_isDragScrolling = false;
        if (m_readyToDragScroll){
            uint64_t nowTime = GetTickCount();
            FCPoint newPoint = getNative()->getTouchPoint();
            if (m_hScrollBar && m_hScrollBar->isVisible()){
				 if(abs(newPoint.x - m_startMovePoint.x) > 50 || m_hScrollBar->getAddSpeed() != 0){
					m_hScrollBar->onAddSpeedScrollStart(m_startMoveTime, nowTime, m_startMovePoint.x, newPoint.x);
				 }
            }
            if (m_vScrollBar && m_vScrollBar->isVisible()){
				if(abs(newPoint.y - m_startMovePoint.y) > 50 || m_vScrollBar->getAddSpeed() != 0){
					m_vScrollBar->onAddSpeedScrollStart(m_startMoveTime, nowTime, m_startMovePoint.y, newPoint.y);
				}
            }
            m_readyToDragScroll = false;
			invalidate();
        }
	}

	void FCDiv::onDragScrolling(){
		int width = getWidth(), height = getHeight();
        if (m_allowDragScroll && m_readyToDragScroll){
            if (!onDragScrollPermit()){
                m_readyToDragScroll = false;
                return;
            }
            bool paint = false;
            FCPoint newPoint = getNative()->getTouchPoint();
            if (m_hScrollBar && m_hScrollBar->isVisible()){		
				if(abs(newPoint.x - m_startMovePoint.x) > width / 10){
                    m_isDragScrolling2 = true;
					m_native->m_touchDownView = this;
                    m_native->m_touchMoveView = this;
                    m_native->m_focusedView = this;
                }
				int newPos = m_startMovePosX + m_startMovePoint.x - newPoint.x;
				if(newPos != m_hScrollBar->getPos()){
					m_hScrollBar->setPos(newPos);
					m_hScrollBar->update();
					paint = true;
				}
            }
            if (m_vScrollBar && m_vScrollBar->isVisible()){
				if (abs(newPoint.y - m_startMovePoint.y) > height / 10){
                    m_isDragScrolling2 = true;
					m_native->m_touchDownView = this;
                    m_native->m_touchMoveView = this;
                    m_native->m_focusedView = this;
                }
				int newPos = m_startMovePosY + m_startMovePoint.y - newPoint.y;
				if(newPos != m_vScrollBar->getPos()){
					m_vScrollBar->setPos(newPos);
					m_vScrollBar->update();
					paint = true;
				}
            }
            if (paint){
				m_isDragScrolling = true;
                invalidate();
            }
        }
	}

	bool FCDiv::onDragScrollPermit(){
        FCView *focusedView = getNative()->getFocusedView();
        if (focusedView){
            if (focusedView->isDragging()){
                return false;
            }
            if (dynamic_cast<FCGridColumn*>(focusedView)){
                return false;
            }
            if (focusedView->getParent()){
                if (dynamic_cast<FCScrollBar*>(focusedView->getParent())){
                    return false;
                }
            }
        }
        return true;
	}

	void FCDiv::onDragScrollStart(){
		m_isDragScrolling = false;
		m_isDragScrolling2 = false;
        FCView *focusedView = getNative()->getFocusedView();
		if (m_hScrollBar && m_hScrollBar->isVisible()){
            if (focusedView == m_hScrollBar->getAddButton()
                || focusedView == m_hScrollBar->getReduceButton()
                || focusedView == m_hScrollBar->getBackButton()
                || focusedView == m_hScrollBar->getScrollButton()){
                m_hScrollBar->setAddSpeed(0);
                return;
            }
        }
        if (m_vScrollBar && m_vScrollBar->isVisible()){
            if (focusedView == m_vScrollBar->getAddButton()
         || focusedView == m_vScrollBar->getReduceButton()
         || focusedView == m_vScrollBar->getBackButton()
         || focusedView == m_vScrollBar->getScrollButton()){
                m_vScrollBar->setAddSpeed(0);
                return;
            }
        }
        if (m_allowDragScroll){
            if (m_hScrollBar && m_hScrollBar->isVisible()){
                m_startMovePosX = m_hScrollBar->getPos();
                m_hScrollBar->setAddSpeed(0);
                m_readyToDragScroll = true;
            }
            if (m_vScrollBar && m_vScrollBar->isVisible()){
                m_startMovePosY = m_vScrollBar->getPos();
                m_vScrollBar->setAddSpeed(0);
                m_readyToDragScroll = true;
            }
            if (m_readyToDragScroll){
                m_startMovePoint = getNative()->getTouchPoint();
                m_startMoveTime = GetTickCount();
            }
        }
	}

	void FCDiv::onKeyDown(char key){
		FCView::onKeyDown(key);
		FCHost *host = getNative()->getHost();
		if(!host->isKeyPress(VK_CONTROL)
		&& !host->isKeyPress(VK_MENU)
		&& !host->isKeyPress(VK_SHIFT)){
			if (key == 38){
				lineUp();
			}
			else if (key == 40){
				lineDown();
			}
			invalidate();
		}
	}

	void FCDiv::onTouchDown(FCTouchInfo touchInfo){
		FCView::onTouchDown(touchInfo);
	    if (!allowPreviewsEvent()){
            onDragScrollStart();
        }
	}

	void FCDiv::onTouchMove(FCTouchInfo touchInfo){
		FCView::onTouchMove(touchInfo);
		if (!allowPreviewsEvent()){
            onDragScrolling();
        }
	}

	void FCDiv::onTouchUp(FCTouchInfo touchInfo){
		FCView::onTouchUp(touchInfo);
	    if (!allowPreviewsEvent()){
            onDragScrollEnd();
        }
	}

	void FCDiv::onTouchWheel(FCTouchInfo touchInfo){
		FCView::onTouchWheel(touchInfo);
        if(m_vScrollBar && m_vScrollBar->isVisible()){
            if (touchInfo.m_delta > 0){
                lineUp();
            }
            else if (touchInfo.m_delta < 0){
                lineDown();
            }
        }else if(m_hScrollBar && m_hScrollBar->isVisible()){
            if (touchInfo.m_delta > 0){
                lineLeft();
            }
            else if (touchInfo.m_delta < 0){
                lineRight();
            }
        }
	}

	bool FCDiv::onPreviewsTouchEvent(String eventName, FCTouchInfo touchInfo){
		if(callPreviewsTouchEvent(L"onpreviewstouchevent", eventName, touchInfo)){
			return true;
		}
		if (allowPreviewsEvent()){
			if (eventName == L"ontouchdown"){
                onDragScrollStart();
            }
			else if (eventName == L"ontouchmove"){
                onDragScrolling();
            }
			else if (eventName == L"ontouchup"){
				bool state = m_isDragScrolling;
                onDragScrollEnd();
                if (state && !m_isDragScrolling2){
                    return false;
                }
            }
        }
        return false;
	}

	void FCDiv::pageDown(){
		if (m_vScrollBar && m_vScrollBar->isVisible()){
			m_vScrollBar->pageAdd();
		}
	}

	void FCDiv::pageLeft(){
		if (m_hScrollBar && m_hScrollBar->isVisible()){
			m_hScrollBar->pageReduce();
		}
	}

	void FCDiv::pageRight(){
		if (m_hScrollBar && m_hScrollBar->isVisible()){
			m_hScrollBar->pageAdd();
		}
	}

	void FCDiv::pageUp(){
		if (m_vScrollBar && m_vScrollBar->isVisible()){
			m_vScrollBar->pageReduce();
		}
	}

	void FCDiv::setAttribute(const String& name, const String& value){
		if(name == L"allowdragscroll"){
			setAllowDragScroll(FCTran::strToBool(value));
		}
	    else if (name == L"showhscrollbar"){
			setShowHScrollBar(FCTran::strToBool(value));
		}
		else if(name == L"showvscrollbar"){
			setShowVScrollBar(FCTran::strToBool(value));
		}
		else{
			FCView::setAttribute(name, value);
		}
	}

	void FCDiv::update(){
		if(m_native && !m_native->m_lockUpdate){
			FCView::update();
			updateScrollBar();
		}
	}

	void FCDiv::updateScrollBar(){
		if(getNative()){
			FCHScrollBar *hScrollBar = getHScrollBar();
			FCVScrollBar *vScrollBar = getVScrollBar();
			if(isVisible()){
				int width = getWidth(), height = getHeight();
				int hBarHeight = hScrollBar ? hScrollBar->getHeight() : 0;
				int vBarWidth = vScrollBar ? vScrollBar->getWidth() : 0;
				int wmax = getContentWidth(), hmax = getContentHeight();
				if(hScrollBar){
					hScrollBar->setContentSize(wmax);
					FCSize hSize = {width - vBarWidth, hBarHeight};
					hScrollBar->m_size = hSize;
					hScrollBar->setPageSize(width - vBarWidth);
					FCPoint hLocation = {0, height - hBarHeight};
					hScrollBar->m_location = hLocation;
					if (wmax <= width){
						hScrollBar->setVisible(false);
					}
					else{
						hScrollBar->setVisible(true);
					}
				}
				if(vScrollBar){
					vScrollBar->setContentSize(hmax);
					FCSize vSize = {vBarWidth, height - hBarHeight};
					vScrollBar->m_size = vSize;
					vScrollBar->setPageSize(height - hBarHeight);
					FCPoint vLocation = {width - vBarWidth, 0};
					vScrollBar->m_location = vLocation;
					int vh = (hScrollBar && hScrollBar->isVisible()) ? height - hBarHeight : height;
					if (hmax <= vh){
						vScrollBar->setVisible(false);
					}
					else{
						vScrollBar->setVisible(true);
					}
				}
				if (hScrollBar && vScrollBar){
					if (hScrollBar->isVisible() && !vScrollBar->isVisible()){
						hScrollBar->m_size.cx = width;
						hScrollBar->setPageSize(width);
					}
					else if (!hScrollBar->isVisible() && vScrollBar->isVisible()){
						vScrollBar->m_size.cy = height;
						vScrollBar->setPageSize(height);
					}
				}
				if(hScrollBar && hScrollBar->isVisible()){
					hScrollBar->update();
				}
				if(vScrollBar && vScrollBar->isVisible()){
					vScrollBar->update();
				}
			}
		}
	}
}
